package com.ww.springboot.sharding.config;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import com.google.common.collect.Range;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;

import java.util.*;

/**
 * 每条新增 查询数据都会根据此策略分配表名
 *
 * @author liw
 * @date 2020/8/3 14:08
 */
public class OrderRangeAlgorithm2 implements ComplexKeysShardingAlgorithm<Date> {


    /**
     * 出库时间列
     */
    private final String COLUMN_NAME_OUT_STOCK = "o_outstock_time";

    /**
     * 付款时间列
     */
    private final String COLUMN_NAME_PAID_TIME = "o_paid_time";


    /**
     * @param collection               全量配置表
     * @param complexKeysShardingValue 分片值
     * @return
     */
    @Override
    public Collection<String> doSharding(Collection<String> collection,
                                         ComplexKeysShardingValue<Date> complexKeysShardingValue) {
        //返回多个值 则表示多个表同时插入相同的值
        return collection;
    }

    private boolean rangeStrategy(Collection<String> collection, Map<String, Range<Date>> columnNameAndRangeValuesMap, List<String> tableNames) {
        // 如果包含出库时间列 根据出库时间列按月份路由 查询出库时间当月的表
        if (columnNameAndRangeValuesMap.containsKey(COLUMN_NAME_OUT_STOCK)) {
            Range<Date> dateRange = columnNameAndRangeValuesMap.get(COLUMN_NAME_OUT_STOCK);
            // 最小出库时间
            Date minDate = dateRange.lowerEndpoint();
            // 最大出库时间
            Date maxDate = dateRange.upperEndpoint();
            // 最小季度
            int minQuarter = DateUtil.month(minDate) / 3 + 1;
            // 最大季度
            int maxQuarter = DateUtil.month(maxDate) / 3 + 1;
            // 起始年份
            int minYear = DateUtil.year(minDate);
            // 结束年份
            int maxYear = DateUtil.year(maxDate);
            for (String tableName : collection) {
                // 表名根据下划线拆分
                String[] s = tableName.split("_");
                // 倒数第二个是年份
                int year = Integer.parseInt(s[s.length - 2]);
                // 倒数第一个是季度
                int quarter = 1;
                // 判断是否在范围内
                boolean flag = minYear <= year && maxYear >= year && minQuarter <= quarter && maxQuarter >= quarter;
                if (flag) {
                    tableNames.add(tableName);
                }
            }
            return true;
        }
        // 包含付款时间列的时候 由于付款时间之后可能出现很长时间未出库的情况 默认查询付款时间当季度和下季度的表
        if (columnNameAndRangeValuesMap.containsKey(COLUMN_NAME_PAID_TIME)) {
            Range<Date> dateRange = columnNameAndRangeValuesMap.get(COLUMN_NAME_PAID_TIME);
            // 最小付款时间
            Date minDate = dateRange.lowerEndpoint();
            // 最大付款时间
            Date maxDate = dateRange.upperEndpoint();
            // 最小季度
            int minQuarter = DateUtil.month(minDate) / 3 + 1;
            // 最大季度
            int maxQuarter = DateUtil.month(maxDate) / 3 + 1 + 1;
            // 起始年份
            int minYear = DateUtil.year(minDate);
            // 结束年份
            int maxYear = DateUtil.year(maxDate);
            for (String tableName : collection) {
                // 表名根据下划线拆分
                String[] s = tableName.split("_");
                // 倒数第二个是年份
                int year = Integer.parseInt(s[s.length - 2]);
                // 倒数第一个是季度
                int quarter = 1;
                // 判断是否在范围内
                boolean flag = minYear <= year && maxYear >= year && minQuarter <= quarter && maxQuarter >= quarter;
                if (flag) {
                    tableNames.add(tableName);
                }
            }
            return true;
        }
        return false;
    }

    private boolean shardingStrategy(Collection<String> collection, Map<String, Collection<Date>> columnNameAndShardingValuesMap, List<String> tableNames) {
        if (columnNameAndShardingValuesMap.containsKey(COLUMN_NAME_OUT_STOCK)) {
            Collection<Date> dates = columnNameAndShardingValuesMap.get(COLUMN_NAME_OUT_STOCK);
            List<Date> sort = CollUtil.sort(dates, Comparator.comparing(Date::getTime));
            // 最小出库时间
            Date minDate = sort.get(0);
            // 最大出库时间
            Date maxDate = sort.get(sort.size() - 1);
            // 最小季度
            int minQuarter = DateUtil.month(minDate) / 3 + 1;
            // 最大季度
            int maxQuarter = DateUtil.month(maxDate) / 3 + 1;
            // 起始年份
            int minYear = DateUtil.year(minDate);
            // 结束年份
            int maxYear = DateUtil.year(maxDate);
            for (String tableName : collection) {
                // 表名根据下划线拆分
                String[] s = tableName.split("_");
                // 倒数第二个是年份
                int year = Integer.parseInt(s[s.length - 2]);
                // 倒数第一个是季度
                int quarter = Integer.parseInt(s[s.length - 1].substring(1));
                // 判断是否在范围内
                boolean flag = minYear <= year && maxYear >= year && minQuarter <= quarter && maxQuarter >= quarter;
                if (flag) {
                    tableNames.add(tableName);
                }
            }
            return true;
        }
        // 包含付款时间列的时候 由于付款时间之后可能出现很长时间未出库的情况 默认查询付款时间当季度和下季度的表
        if (columnNameAndShardingValuesMap.containsKey(COLUMN_NAME_PAID_TIME)) {
            Collection<Date> dates = columnNameAndShardingValuesMap.get(COLUMN_NAME_PAID_TIME);
            List<Date> sort = CollUtil.sort(dates, Comparator.comparing(Date::getTime));
            // 最小出库时间
            Date minDate = sort.get(0);
            // 最大出库时间
            Date maxDate = sort.get(sort.size() - 1);
            // 最小季度
            int minQuarter = DateUtil.month(minDate) / 3 + 1;
            // 最大季度 付款时间可能和出库时间不在同一个季度
            int maxQuarter = DateUtil.month(maxDate) / 3 + 1 + 1;
            // 起始年份
            int minYear = DateUtil.year(minDate);
            // 结束年份
            int maxYear = DateUtil.year(maxDate);
            for (String tableName : collection) {
                // 表名根据下划线拆分
                String[] s = tableName.split("_");
                // 倒数第二个是年份
                int year = Integer.parseInt(s[s.length - 2]);
                // 倒数第一个是季度
                int quarter = 1;
                // 判断是否在范围内
                boolean flag = minYear <= year && maxYear >= year && minQuarter <= quarter && maxQuarter >= quarter;
                if (flag) {
                    tableNames.add(tableName);
                }
            }
            return true;
        }
        return false;
    }
}
